#include "servlet.h"
#include <mutex>
#include <shared_mutex>
#include <utility>
#include <fnmatch.h>    //模糊匹配

#include "../log.h"

namespace MYHTTP
{

FunctionServlet::FunctionServlet(callback cb)
:Servlet("FunctionServlet")
,m_cb(cb)
{}

int32_t FunctionServlet::handle(HttpRequest::ptr request
                                ,HttpResponse::ptr response
                                ,HttpSession::ptr session)
{
    return m_cb(request, response, session);
}

//=========================================================================

ServletDispatch::ServletDispatch():Servlet("ServletDispatch")
{
    m_default.reset(new NotFoundServlet("lightning/1.0"));
}

int32_t ServletDispatch::handle(HttpRequest::ptr request
            ,HttpResponse::ptr response
            ,HttpSession::ptr session)
{
    auto slt = getMatchedServlet(request->getPath());
    if(slt)
    {
        slt->handle(request, response, session);
    }
    else 
    {
        log_error("getMatchedServlet error, uri:{}", request->getPath());
        return -1;
    }

    return 0;
}

//添加servlet
void ServletDispatch::addServlet(const std::string& uri, Servlet::ptr slt)
{
    std::unique_lock<std::shared_mutex> write_lock(m_sharedMutex);
    m_datas[uri] = std::make_shared<HoldServletCreator>(slt);
}

void ServletDispatch::addServlet(const std::string& uri, FunctionServlet::callback cb)
{
    std::unique_lock<std::shared_mutex> write_lock(m_sharedMutex);
    m_datas[uri] = std::make_shared<HoldServletCreator>(
                        std::make_shared<FunctionServlet>(cb));
}


//添加模糊匹配servlet
void ServletDispatch::addGlobServlet(const std::string& uri, Servlet::ptr slt)
{
    std::unique_lock<std::shared_mutex> write_lock(m_sharedMutex);
    for(auto it = m_globs.begin(); it != m_globs.end(); ++it)
    {
        if(it->first == uri)
        {
            m_globs.erase(it);
            break;
        }
    }
    m_globs.emplace_back(std::make_pair(uri, std::make_shared<HoldServletCreator>(slt)));
}

void ServletDispatch::addGlobServlet(const std::string& uri, FunctionServlet::callback cb)
{
    addGlobServlet(uri, std::make_shared<FunctionServlet>(cb));
}


//删除servlet
void ServletDispatch::delServlet(const std::string& uri)
{
    std::unique_lock<std::shared_mutex> write_lock(m_sharedMutex);
    m_datas.erase(uri);
}

void ServletDispatch::delGlobServlet(const std::string& uri)
{
    std::unique_lock<std::shared_mutex> write_lock(m_sharedMutex);
    for(auto it = m_globs.begin(); it != m_globs.end(); ++it)
    {
        if(it->first == uri)
        {
            m_globs.erase(it);
            break;
        }
    }
}



//通过uri获取servlet
Servlet::ptr ServletDispatch::getServlet(const std::string& uri)
{
    std::shared_lock<std::shared_mutex> read_lock(m_sharedMutex);
    auto it = m_datas.find(uri);
    return it == m_datas.end() ? nullptr : it->second->get();
}

//通过uri获取模糊匹配servlet
Servlet::ptr ServletDispatch::getGlobServlet(const std::string& uri)
{
    std::shared_lock<std::shared_mutex> read_lock(m_sharedMutex);
    for(auto it = m_globs.begin(); it != m_globs.end(); ++it)
    {
        //fnmatch 能够处理复杂的文件名模式匹配，而不仅仅是简单的字符串相等比较。
        //例如，如果 it->first 是 "*.txt"，那么 fnmatch 会匹配所有以 .txt 结尾的字符串，而不仅仅是字面值 "*.txt"。
        if(!fnmatch(it->first.c_str(), uri.c_str(), 0)) //0 表示使用默认的匹配行为。
        {
            return it->second->get();
        }
    }
    return nullptr;
}

//通过uri获取servlet
Servlet::ptr ServletDispatch::getMatchedServlet(const std::string& uri)
{
    std::shared_lock<std::shared_mutex> read_lock(m_sharedMutex);
    auto mit = m_datas.find(uri);
    if(mit != m_datas.end())
    {
        return mit->second->get();
    }
    for(auto it = m_globs.begin(); it != m_globs.end(); ++it)
    {
        if(!fnmatch(it->first.c_str(), uri.c_str(), 0))
        {
            return it->second->get();
        }
    }
    return m_default;
}



void ServletDispatch::addServletCreator(const std::string& uri, IServletCreator::ptr creator)
{
    
}

void ServletDispatch::addGlobServletCreator(const std::string& uri, IServletCreator::ptr creator)
{
    
}



void ServletDispatch::listAllServletCreator(std::map<std::string, IServletCreator::ptr>& infos)
{
    
}

void ServletDispatch::listAllGlobServletCreator(std::map<std::string, IServletCreator::ptr>& infos)
{
    
}


//=========================================================================

NotFoundServlet::NotFoundServlet(const std::string& name)
:Servlet("NotFoundServlet")
,m_name(name)
{
    m_content = "<html><head><title>404 Not Found"
        "</title></head><body><center><h1>404 Not Found</h1></center>"
        "<hr><center>" + name + "</center></body></html>";
}

int32_t NotFoundServlet::handle(HttpRequest::ptr request
            ,HttpResponse::ptr response
            ,HttpSession::ptr session)
{
    response->setStatus(HttpStatus::NOT_FOUND);
    response->setHeader("Server", "Lightning/1.0.0");
    response->setHeader("Content-Type", "text/html");
    response->setBody(m_content);
    return 0;
}


} //MYHTTP